package com.coderly.onlinegallerysharingplatform.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coderly.onlinegallerysharingplatform.common.constant.SpaceUserPermissionConstant;
import com.coderly.onlinegallerysharingplatform.common.convention.errorcode.ErrorCode;
import com.coderly.onlinegallerysharingplatform.common.convention.exception.BizException;
import com.coderly.onlinegallerysharingplatform.enums.PictureReviewStatusEnum;
import com.coderly.onlinegallerysharingplatform.enums.SpaceTypeEnum;
import com.coderly.onlinegallerysharingplatform.enums.UserRoleEnum;
import com.coderly.onlinegallerysharingplatform.event.ViewPictureEvent;
import com.coderly.onlinegallerysharingplatform.model.dao.entity.*;
import com.coderly.onlinegallerysharingplatform.model.dao.mapper.PictureLikeMapper;
import com.coderly.onlinegallerysharingplatform.model.dao.mapper.PictureMapper;
import com.coderly.onlinegallerysharingplatform.model.dao.mapper.PictureShareMapper;
import com.coderly.onlinegallerysharingplatform.model.dto.req.pic.*;
import com.coderly.onlinegallerysharingplatform.model.dto.resp.pic.PicOperationResult;
import com.coderly.onlinegallerysharingplatform.model.dto.resp.pic.PictureRespDTO;
import com.coderly.onlinegallerysharingplatform.model.dto.resp.user.UserRespDTO;
import com.coderly.onlinegallerysharingplatform.common.oss.template.FilePictureUpload;
import com.coderly.onlinegallerysharingplatform.common.oss.template.PictureUploadTemplate;
import com.coderly.onlinegallerysharingplatform.common.oss.template.URLPictureUpload;
import com.coderly.onlinegallerysharingplatform.service.*;
import com.coderly.onlinegallerysharingplatform.toolkit.ExceptionTrowUtils;
import com.coderly.onlinegallerysharingplatform.toolkit.StpKit;
import com.coderly.onlinegallerysharingplatform.toolkit.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * @author 26788
 * @description 针对表【t_picture(图片表)】的数据库操作Service实现
 * @createDate 2025-03-07 11:27:18
 */
@Service
@Slf4j
public class PictureServiceImpl extends ServiceImpl<PictureMapper, PictureDO>
        implements PictureService {

    @Resource
    private UserService userService;
    @Resource
    private PictureMapper pictureMapper;
    @Resource
    private PictureLikeMapper pictureLikeMapper;
    @Resource
    private SpaceService spaceService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private PictureShareMapper pictureShareMapper;
    @Resource
    private ApplicationEventPublisher eventPublisher;
    @Resource(name = "taskExecutor")  // 按名称注入 "taskExecutor"
    private Executor taskExecutor;

    @Resource
    private FilePictureUpload filePictureUpload;
    @Resource
    private URLPictureUpload urlPictureUpload;

    @Override
    public PictureRespDTO uploadPicture(Object pictureSource, UploadPictureReqDTO uploadPictureReqDTO) {
        Long pictureId = uploadPictureReqDTO.getId();
        Long spaceId = uploadPictureReqDTO.getSpaceId();
        Long loginUserId = UserUtil.getLoginUserId();
        SpaceDO spaceDO = null;
        // 仅校验非公共空间
        if (spaceId != null) {
            spaceDO = spaceService.getById(spaceId);
            // 校验空间权限
            validateSpacePermission(spaceDO, loginUserId, SpaceUserPermissionConstant.PICTURE_UPLOAD, "上传");
            // 校验空间额度
            validateSpaceQuota(spaceDO);
        }
        if(pictureId != null) {
            // 校验更新场景
            validateUpdateScenario(pictureId, spaceId, loginUserId);
            // 异步清除OSS服务器资源
            taskExecutor.execute(() -> {
                final PictureUploadTemplate pictureUploadTemplate = null;
                // 异步清除服务器已经保存的图片
                Boolean deletePicture = pictureUploadTemplate.deletePicture(pictureId);
                ExceptionTrowUtils.throwIf(!deletePicture, ErrorCode.OPERATION_ERROR, "删除图片资源失败");
            });
        }

        // 根据图片输入源的类型动态调整上传参数
        PictureUploadTemplate pictureUploadTemplate = filePictureUpload; // 默认是文件上传
        // 根据空间划分目录，上传图片
        String uploadPathPrefix = buildUploadPath(spaceDO);
        if (pictureSource instanceof String) {
            pictureUploadTemplate = urlPictureUpload;
        }
        PicOperationResult picOperationResult = pictureUploadTemplate.uploadPicture(pictureSource, uploadPathPrefix);

        // 构造入库信息
        PictureDO pictureDO = buildAndSavePicture(picOperationResult, spaceId, loginUserId, pictureId);


        return PictureRespDTO.obj2RespDTO(pictureDO);
    }

    /**
     * 校验用户对指定空间的访问/操作权限
     *
     * @param spaceDO 空间实体对象
     * @param loginUserId 当前登录用户ID
     * @param requiredPermission 需要的权限(可为null，表示只需要基础访问权限)
     * @param operationName 操作名称(用于错误提示，如"上传"、"查看"等)
     * @throws BizException 当权限校验失败时抛出
     */
    private void validateSpacePermission(SpaceDO spaceDO,
                                         Long loginUserId,
                                         String requiredPermission,
                                         String operationName) {

        ExceptionTrowUtils.throwIf(spaceDO == null, ErrorCode.NOT_FOUND_ERROR, "未找到指定上传的空间");
        SpaceTypeEnum spaceType = SpaceTypeEnum.getEnumByValue(spaceDO.getSpaceType());
        ExceptionTrowUtils.throwIf(spaceType == null, ErrorCode.PARAMS_ERROR);
        // 空间权限校验
        switch (spaceType) {
            case PRIVATE:
                // 仅本人可以操作
                if (!loginUserId.equals(spaceDO.getUserId())) {
                    throw new BizException(ErrorCode.NO_AUTH_ERROR,
                            String.format("无%s权限", operationName));
                }
                break;
            case TEAM:
                // 仅团队内有上传权限才可以操作
                if (!StpKit.SPACE.hasPermission(requiredPermission)) {
                    throw new BizException(ErrorCode.NO_AUTH_ERROR, String.format("无%s权限", operationName));
                }
                break;
            default:
                // 理论不会执行
                throw new BizException(ErrorCode.PARAMS_ERROR, "未知的空间类型");
        }
    }

    /**
     * 校验空间额度是否足够
     * @param spaceDO 空间对象
     */
    private void validateSpaceQuota(SpaceDO spaceDO) {
        if (spaceDO.getTotalCount() >=  spaceDO.getMaxCount() || spaceDO.getTotalSize() >= spaceDO.getMaxSize()) {
            throw new BizException(ErrorCode.OPERATION_ERROR, "空间大小不足");
        }
    }

    /**
     * 校验更新场景
     * @param pictureId
     * @param spaceId
     * @param loginUserId
     */
    private void validateUpdateScenario(Long pictureId, Long spaceId, Long loginUserId) {
        PictureDO oldPicture = this.getById(pictureId);
        ExceptionTrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);

        // 校验上传一致性
        if (ObjUtil.notEqual(spaceId, oldPicture.getSpaceId())) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "上传空间不一致");
        }
    }

    /**
     * 根据空间ID和空间类型构建上传路径
     *
     * @param spaceDO 空间对象
     * @return 格式化后的上传路径字符串
     * @throws BizException 当传入无效的空间类型时抛出异常
     */
    private String buildUploadPath(SpaceDO spaceDO) {
        Long spaceId = null;
        Integer spaceType = null;
        if (spaceDO != null) {
            spaceId = spaceDO.getId();
            spaceType = spaceDO.getSpaceType();
        }
        // 公共空间路径格式: public/{userId}
        if (spaceId == null) {
            return String.format("public/%s", UserUtil.getLoginUserId());
        }

        // 根据空间类型构建不同路径
        SpaceTypeEnum type = SpaceTypeEnum.getEnumByValue(spaceType);
        ExceptionTrowUtils.throwIf(type == null, ErrorCode.PARAMS_ERROR, "无效的空间类型");

        switch (type) {
            case PRIVATE:
                // 私有空间路径格式: space/{spaceId}
                return String.format("space/%s", spaceId);
            case TEAM:
                // 团队空间路径格式: team/{spaceId}
                return String.format("team/%s", spaceId);
            default:
                // 默认路径格式: default/{userId} (作为后备方案, 理论上不会执行)
                log.error("未知空间类型[{}]，使用默认上传路径", spaceType);
                return String.format("default/%s", UserUtil.getLoginUserId());
        }
    }

    /**
     * 构建并保存图片信息
     */
    private PictureDO buildAndSavePicture(PicOperationResult uploadResult, Long spaceId,
                                          Long loginUserId, Long pictureId) {
        // 构建图片实体
        PictureDO pictureDO = PictureDO.builder()
                .spaceId(spaceId)
                .url(uploadResult.getUrl())
                .thumbnailUrl(uploadResult.getThumbnailUrl())
                .name(uploadResult.getPicName())
                .picSize(uploadResult.getPicSize())
                .picWidth(uploadResult.getPicWidth())
                .picHeight(uploadResult.getPicHeight())
                .picScale(uploadResult.getPicScale())
                .picFormat(uploadResult.getPicFormat())
                .userId(loginUserId)
                .build();

        // 补充审核参数
        this.fillReviewParams(pictureDO, loginUserId, UserUtil.getLoginUserRole());

        // 处理更新场景
        if (pictureId != null) {
            pictureDO.setId(pictureId);
            pictureDO.setEditTime(new Date());
        }

        // 事务处理
        return transactionTemplate.execute(status -> {
            // 保存图片
            boolean saveResult = this.saveOrUpdate(pictureDO);
            ExceptionTrowUtils.throwIf(!saveResult, ErrorCode.OPERATION_ERROR, "图片上传失败");

            // 更新空间额度
            if (spaceId != null) {
                boolean updateResult = spaceService.lambdaUpdate()
                        .eq(SpaceDO::getId, spaceId)
                        .setSql("total_size = total_size + " + pictureDO.getPicSize())
                        .setSql("total_count = total_count + 1")
                        .update();
                ExceptionTrowUtils.throwIf(!updateResult, ErrorCode.OPERATION_ERROR, "额度更新失败");
            }

            return pictureDO;
        });
    }

    /**
     * 填充图片审核参数
     *
     * @param pictureDO 图片实体对象
     * @param loginUserId 当前登录用户ID
     * @param role 当前用户角色
     * 审核规则：
     * 1. 上传到指定空间（spaceId!=null）无需审核，自动通过
     * 2. 公共图库（spaceId=null）需要审核：
     *    - 管理员上传自动通过
     *    - 普通用户需要人工审核
     */
    private void fillReviewParams(PictureDO pictureDO, Long loginUserId, String role) {
        // 上传到指定空间自动通过审核
        if (pictureDO.getSpaceId() != null) {
            pictureDO.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            pictureDO.setReviewerId(loginUserId);
            pictureDO.setReviewTime(new Date());
            pictureDO.setReviewMessage("空间文件自动过审");
            return;
        }

        // 公共图库文件处理
        if (UserRoleEnum.ADMIN.getValue().equals(role)) {
            // 管理员上传自动通过
            pictureDO.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            pictureDO.setReviewerId(loginUserId);
            pictureDO.setReviewTime(new Date());
            pictureDO.setReviewMessage("管理员上传自动过审");
        } else {
            // 普通用户上传需要审核
            pictureDO.setReviewStatus(PictureReviewStatusEnum.REVIEWING.getValue());
        }
    }

    @Override
    public Boolean deletePicture(DeletePictureReqDTO deletePictureReqDTO) {
        long loginUserId = StpUtil.getLoginIdAsLong();
        long id = deletePictureReqDTO.getId();
        // 判断是否存在
        PictureDO oldPicture = this.getById(id);
        ExceptionTrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验权限
        Long spaceId = oldPicture.getSpaceId();
        SpaceDO spaceDO = spaceService.getById(spaceId);
        validateSpacePermission(spaceDO, loginUserId, SpaceUserPermissionConstant.PICTURE_DELETE, "删除");
        // 开启事务
        transactionTemplate.execute(status -> {
            // 操作数据库
            boolean result = this.removeById(id);
            ExceptionTrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
            // 更新空间使用额度
            boolean update = spaceService.lambdaUpdate()
                    .eq(SpaceDO::getId, oldPicture.getSpaceId())
                    .setSql("total_size = total_size - " + oldPicture.getPicSize())
                    .setSql("total_count = total_count - 1")
                    .update();
            ExceptionTrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "额度更新失败");
            return true;
        });

        return true;
    }

    @Override
    public Boolean updatePictureByAdmin(UpdatePictureReqDTO updatePictureReqDTO) {
        // 将实体类和 DTO 进行转换
        PictureDO pictureDO = new PictureDO();
        BeanUtils.copyProperties(updatePictureReqDTO, pictureDO);
        // 注意将 list 转为 string
        pictureDO.setTags(JSONUtil.toJsonStr(updatePictureReqDTO.getTags()));
        // 数据校验
        this.validPicture(pictureDO);
        // 判断是否存在
        long id = updatePictureReqDTO.getId();
        PictureDO oldPicture = this.getById(id);
        ExceptionTrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
        // 补充审核参数
        Long loginUserId = StpUtil.getLoginIdAsLong();
        String role = StpUtil.getRoleList().get(0);
        this.fillReviewParams(pictureDO, loginUserId, role);
        // 操作数据库
        boolean result = this.updateById(pictureDO);
        ExceptionTrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return true;
    }


    @Override
    public Boolean updatePictureByUser(UpdatePictureReqDTO updatePictureReqDTO) {
        // 在此处将实体类和 DTO 进行转换
        PictureDO pictureDO = new PictureDO();
        BeanUtils.copyProperties(updatePictureReqDTO, pictureDO);
        // 注意将 list 转为 string
        pictureDO.setTags(JSONUtil.toJsonStr(updatePictureReqDTO.getTags()));
        // 设置编辑时间
        pictureDO.setEditTime(new Date());
        // 数据校验
        validPicture(pictureDO);
        // 判断是否存在
        long id = updatePictureReqDTO.getId();
        PictureDO oldPicture = this.getById(id);
        ExceptionTrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验权限
        Long loginUserId = UserUtil.getLoginUserId();
        String loginUserRole = UserUtil.getLoginUserRole();
        Long spaceId = oldPicture.getSpaceId();
        if (spaceId != null) {
            SpaceDO spaceDO = spaceService.getById(spaceId);
            validateSpacePermission(spaceDO, loginUserId, SpaceUserPermissionConstant.PICTURE_EDIT, "编辑");
        }
        // 修改后重置审核状态
        fillReviewParams(pictureDO, loginUserId, loginUserRole);
        // 操作数据库
        boolean result = this.updateById(pictureDO);
        ExceptionTrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return true;
    }


    @Override
    public PictureRespDTO getPictureByUserWithId(Long id) {

        PictureDO pictureDO = this.getById(id);
        ExceptionTrowUtils.throwIf(pictureDO == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验图片审核情况
        Long loginUserId = UserUtil.getLoginUserId();
        // 未通过审核前，仅用户本人可浏览
        if (!pictureDO.getUserId().equals(loginUserId) &&
                !pictureDO.getReviewStatus().equals(PictureReviewStatusEnum.PASS.getValue())) {
            throw new BizException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 空间权限校验
        Long spaceId = pictureDO.getSpaceId();
        if (spaceId != null) {
            SpaceDO spaceDO = spaceService.getById(spaceId);
            // 校验权限
            validateSpacePermission(spaceDO, loginUserId, SpaceUserPermissionConstant.PICTURE_VIEW, "浏览");
        }
        // 对象转封装类
        PictureRespDTO pictureRespDTO = PictureRespDTO.obj2RespDTO(pictureDO);
        // 关联查询用户信息
        Long userId = pictureDO.getUserId();
        if (userId != null && userId > 0) {
            UserDO user = userService.getById(userId);
            UserRespDTO userRespDTO = userService.getUser(user);
            pictureRespDTO.setUser(userRespDTO);
        }
        // 发布浏览图片事件
        eventPublisher.publishEvent(new ViewPictureEvent(this, pictureDO.getId()));
        return pictureRespDTO;
    }

    @Override
    public Page<PictureRespDTO> listPicturePageByUser(GetPictureReqDTO getPictureReqDTO) {
        int current = getPictureReqDTO.getCurrent();
        int pageSize = getPictureReqDTO.getPageSize();
        Long spaceId = getPictureReqDTO.getSpaceId();
        Long userId = getPictureReqDTO.getUserId();
        Long loginUserId = null;
        if (StpUtil.isLogin()) {
            loginUserId = UserUtil.getLoginUserId();
        }

        if (userId != null && !userId.equals(loginUserId)) {
            throw new BizException(ErrorCode.NO_AUTH_ERROR, "无权查看其他用户的图片");
        }
        // 操作私有图库和团队图库
        if (spaceId != null)  {
            SpaceDO spaceDO = spaceService.getById(spaceId);
            validateSpacePermission(spaceDO, loginUserId, SpaceUserPermissionConstant.PICTURE_VIEW, "查看");
        } else {
            // 操作公共图库
            getPictureReqDTO.setSpaceIdIsNull(true);
            // 公共图库只能查看审核通过的图片
            getPictureReqDTO.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
        }

        // 查询数据库
        Page<PictureDO> picturePage = this.page(new Page<>(current, pageSize),
                this.buildQueryWrapper(getPictureReqDTO));
        // 获取封装类
        return this.convertToRespPage(picturePage);
    }

    @Override
    public Page<PictureDO> listPicturePageByAdmin(GetPictureReqDTO getPictureReqDTO) {
        long current = getPictureReqDTO.getCurrent();
        long size = getPictureReqDTO.getPageSize();
        // 查询数据库
        return this.page(new Page<>(current, size),
                this.buildQueryWrapper(getPictureReqDTO));
    }

    @Override
    public Page<PictureRespDTO> listPublicApprovedPicturePageByUser(GetPictureReqDTO getPictureReqDTO) {
        long current = getPictureReqDTO.getCurrent();
        long size = getPictureReqDTO.getPageSize();
        // 仅获取上传到公共图库且已通过的图片
        getPictureReqDTO.setSpaceIdIsNull(true);
        getPictureReqDTO.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
        // 数据库分页查询
        Page<PictureDO> picturePage = this.page(new Page<>(current, size),
                this.buildQueryWrapper(getPictureReqDTO));
        // 转换封装类
        return this.convertToRespPage(picturePage);
    }

    @Override
    public Page<PictureRespDTO> listPublicPicturePageByUser(GetPictureReqDTO getPictureReqDTO) {
        long current = getPictureReqDTO.getCurrent();
        long size = getPictureReqDTO.getPageSize();
        // 仅获取上传到公共图库且已通过的图片
        getPictureReqDTO.setSpaceIdIsNull(true);
        // 数据库分页查询
        Page<PictureDO> picturePage = this.page(new Page<>(current, size),
                this.buildQueryWrapper(getPictureReqDTO));
        // 转换封装类
        return this.convertToRespPage(picturePage);
    }


    @Override
    public void reviewPictureByAdmin(ReviewPictureReqDTO reviewPictureReqDTO) {
        // 获取登录用户
        long loginUserId = UserUtil.getLoginUserId();
        Long id = reviewPictureReqDTO.getId();
        Integer reviewStatus = reviewPictureReqDTO.getReviewStatus();
        String reviewMessage = reviewPictureReqDTO.getReviewMessage();
        PictureReviewStatusEnum statusEnum = PictureReviewStatusEnum.getEnumByValue(reviewStatus);
        // 系统默认不允许将已经审核的图片再改为待审核
        if (id == null || statusEnum == null || PictureReviewStatusEnum.REVIEWING.equals(reviewStatus)) {
            throw new BizException(ErrorCode.PARAMS_ERROR);
        }
        // 2. 判断图片是否存在
        PictureDO oldPicture = this.getById(id);
        ExceptionTrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
        // 3. 校验审核状态是否重复
        // 判断当前状态是否与老状态一致
        if (oldPicture.getReviewStatus().equals(reviewStatus)) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "请勿重复审核");
        }
        // 4. 入库
        // 重新new一个对象，只赋值需要修改的字段，节省效率
        PictureDO updatePicture = new PictureDO();
        BeanUtil.copyProperties(reviewPictureReqDTO, updatePicture);
        updatePicture.setReviewerId(loginUserId);
        updatePicture.setReviewTime(new Date());
        boolean updated = this.updateById(updatePicture);
        ExceptionTrowUtils.throwIf(!updated, ErrorCode.OPERATION_ERROR);
    }



    @Override
    @Transactional
    public Boolean likePicture(LikePictureReqDTO request) {
        final Long pictureId = request.getId();
        final Long userId = UserUtil.getLoginUserId();

        // 1. 校验图片是否存在
        PictureDO picture = pictureMapper.selectById(pictureId);
        if (picture == null) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "图片不存在");
        }

        // 2. 查询点赞记录
        PictureLikeDO likeRecord = pictureLikeMapper.selectOne(
                Wrappers.<PictureLikeDO>lambdaQuery()
                        .eq(PictureLikeDO::getUserId, userId)
                        .eq(PictureLikeDO::getPictureId, pictureId)
        );

        // 3. 已存在有效点赞直接返回
        if (likeRecord != null && likeRecord.getIsLiked() == 1) {
            return false;
        }

        // 4. 更新图片点赞数（原子操作）
        int updateCount = pictureMapper.update(null,
                Wrappers.<PictureDO>lambdaUpdate()
                        .setSql("like_count = like_count + 1")
                        .eq(PictureDO::getId, pictureId)
        );

        // 5. 更新或创建点赞记录
        if (likeRecord != null) {
            // 存在历史记录则更新状态
            likeRecord.setIsLiked(1);
            pictureLikeMapper.updateById(likeRecord);
        } else {
            // 新建点赞记录
            pictureLikeMapper.insert(PictureLikeDO.builder()
                    .userId(userId)
                    .pictureId(pictureId)
                    .isLiked(1)
                    .createTime(new Date())
                    .build());
        }

        return updateCount > 0;
    }

    @Override
    @Transactional
    public Boolean unLikePicture(UnLikePictureReqDTO unLikePictureReqDTO) {
        Long pictureId = unLikePictureReqDTO.getId();
        // 检查图片是否存在
        PictureDO pictureDO = pictureMapper.selectById(pictureId);
        if (pictureDO == null) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "图片不存在");
        }

        Long userId = UserUtil.getLoginUserId();
        // 查询用户的点赞记录
        LambdaQueryWrapper<PictureLikeDO> queryWrapper = Wrappers.lambdaQuery(PictureLikeDO.class)
                .eq(PictureLikeDO::getUserId, userId)
                .eq(PictureLikeDO::getPictureId, pictureId);
        PictureLikeDO likeRecord = pictureLikeMapper.selectOne(queryWrapper);

        // 用户未点赞或已取消，直接返回
        if (likeRecord == null || likeRecord.getIsLiked() == 0) {
            return true;
        }

        // 减少点赞数（确保点赞数不为负）
        boolean updateSuccess = pictureMapper.update(null,
                Wrappers.lambdaUpdate(PictureDO.class)
                        .setSql("like_count = like_count - 1")
                        .eq(PictureDO::getId, pictureId)
                        .gt(PictureDO::getLikeCount, 0)) > 0;

        // 更新点赞状态为取消
        likeRecord.setIsLiked(0);
        boolean updateLike = pictureLikeMapper.updateById(likeRecord) > 0;

        return updateSuccess && updateLike;
    }





    @Override
    public Boolean sharePicture(SharePictureReqDTO sharePictureReqDTO) {
        final Long pictureId = sharePictureReqDTO.getId();
        final Long userId = UserUtil.getLoginUserId();

        // 1. 校验图片是否存在
        PictureDO picture = pictureMapper.selectById(pictureId);
        if (picture == null) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "图片不存在");
        }

        // 2. 查询点赞记录
        PictureShareDO shareRecord = pictureShareMapper.selectOne(
                Wrappers.<PictureShareDO>lambdaQuery()
                        .eq(PictureShareDO::getUserId, userId)
                        .eq(PictureShareDO::getPictureId, pictureId)
        );

        // 3. 已存在有效分享直接返回
        if (shareRecord != null && shareRecord.getIsShared() == 1) {
            return true;
        }

        // 4. 更新图片分享数（原子操作）
        int updateCount = pictureMapper.update(null,
                Wrappers.<PictureDO>lambdaUpdate()
                        .setSql("share_count = share_count + 1")
                        .eq(PictureDO::getId, pictureId)
        );

        // 5. 更新或创建分享记录
        if (shareRecord != null) {
            // 存在历史记录则更新状态
            shareRecord.setIsShared(1);
            pictureShareMapper.updateById(shareRecord);
        } else {
            // 新建分享记录
            pictureShareMapper.insert(PictureShareDO.builder()
                    .userId(userId)
                    .pictureId(pictureId)
                    .isShared(1)
                    .createTime(new Date())
                    .build());
        }

        return updateCount > 0;
    }

    @Override
    public Boolean unSharePicture(UnSharePictureReqDTO unSharePictureReqDTO) {
        Long pictureId = unSharePictureReqDTO.getId();
        // 检查图片是否存在
        PictureDO pictureDO = pictureMapper.selectById(pictureId);
        if (pictureDO == null) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "图片不存在");
        }

        Long userId = UserUtil.getLoginUserId();
        // 查询用户的点赞记录
        PictureShareDO shareRecord = pictureShareMapper.selectOne(
                Wrappers.lambdaQuery(PictureShareDO.class)
                .eq(PictureShareDO::getUserId, userId)
                .eq(PictureShareDO::getPictureId, pictureId));

        // 用户未点赞或已取消，直接返回
        if (shareRecord == null || shareRecord.getIsShared() == 0) {
            return true;
        }

        // 减少点赞数（确保点赞数不为负）
        boolean updateSuccess = pictureMapper.update(null,
                Wrappers.lambdaUpdate(PictureDO.class)
                        .setSql("share_count = share_count - 1")
                        .eq(PictureDO::getId, pictureId)
                        .gt(PictureDO::getLikeCount, 0)) > 0;

        // 更新点赞状态为取消
        shareRecord.setIsShared(0);
        boolean updateShare = pictureShareMapper.updateById(shareRecord) > 0;
        return updateSuccess && updateShare;
    }

    /**
     * 构建查询条件
     * @param getPictureReqDTO
     * @return
     */
    private QueryWrapper<PictureDO> buildQueryWrapper(GetPictureReqDTO getPictureReqDTO) {
        QueryWrapper<PictureDO> queryWrapper = new QueryWrapper<>();
        if (getPictureReqDTO == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = getPictureReqDTO.getId();
        String name = getPictureReqDTO.getName();
        String introduction = getPictureReqDTO.getIntroduction();
        String category = getPictureReqDTO.getCategory();
        List<String> tags = getPictureReqDTO.getTags();
        Long picSize = getPictureReqDTO.getPicSize();
        Integer picWidth = getPictureReqDTO.getPicWidth();
        Integer picHeight = getPictureReqDTO.getPicHeight();
        Double picScale = getPictureReqDTO.getPicScale();
        String picFormat = getPictureReqDTO.getPicFormat();
        String searchText = getPictureReqDTO.getSearchText();
        Long userId = getPictureReqDTO.getUserId();
        Integer reviewStatus = getPictureReqDTO.getReviewStatus();
        String reviewMessage = getPictureReqDTO.getReviewMessage();
        Long reviewerId = getPictureReqDTO.getReviewerId();
        Date reviewTime = getPictureReqDTO.getReviewTime();
        String sortField = getPictureReqDTO.getSortField();
        String sortOrder = getPictureReqDTO.getSortOrder();
        Long spaceId = getPictureReqDTO.getSpaceId();
        boolean spaceIdIsNull = getPictureReqDTO.isSpaceIdIsNull();


        // 从多字段中搜索
        if (StrUtil.isNotBlank(searchText)) {
            // 需要拼接查询条件
            queryWrapper.and(qw -> qw.like("name", searchText)
                    .or()
                    .like("introduction", searchText)
            );
        }
        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(userId), "user_id", userId);
        queryWrapper.eq(ObjUtil.isNotEmpty(spaceId), "space_id", spaceId);
        queryWrapper.isNull(spaceIdIsNull, "space_id"); // 是否只查询spaceId为null
        queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
        queryWrapper.like(StrUtil.isNotBlank(introduction), "introduction", introduction);
        queryWrapper.like(StrUtil.isNotBlank(picFormat), "pic_format", picFormat);
        queryWrapper.like(StrUtil.isNotBlank(reviewMessage), "review_messages", reviewMessage);
        queryWrapper.eq(StrUtil.isNotBlank(category), "category", category);
        queryWrapper.eq(ObjUtil.isNotEmpty(picWidth), "pic_width", picWidth);
        queryWrapper.eq(ObjUtil.isNotEmpty(picHeight), "pic_height", picHeight);
        queryWrapper.eq(ObjUtil.isNotEmpty(picSize), "pic_size", picSize);
        queryWrapper.eq(ObjUtil.isNotEmpty(picScale), "pic_scale", picScale);
        queryWrapper.eq(ObjUtil.isNotEmpty(reviewStatus), "review_status", reviewStatus);
        queryWrapper.eq(ObjUtil.isNotEmpty(reviewerId), "reviewer_id", reviewerId);
        // JSON 数组查询
        if (CollUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                queryWrapper.like("tags", "\"" + tag + "\"");
            }
        }
        // 排序
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }


    /**
     * 数据库分页对象转封装分页对象
     * @param picturePage
     * @return
     */
    private Page<PictureRespDTO> convertToRespPage(Page<PictureDO> picturePage) {
        List<PictureDO> pictureList = picturePage.getRecords();
        Page<PictureRespDTO> PictureRespDTOPage = new Page<>(picturePage.getCurrent(), picturePage.getSize(), picturePage.getTotal());
        if (CollUtil.isEmpty(pictureList)) {
            return PictureRespDTOPage;
        }
        // 对象列表 => 封装对象列表
        List<PictureRespDTO> PictureRespDTOList = pictureList.stream().map(PictureRespDTO::obj2RespDTO).collect(Collectors.toList());
        // 获取当前登录用户
        Long loginUserID = null;
        if (StpUtil.isLogin()) {
            loginUserID = StpUtil.getLoginIdAsLong();
        }

        // 获取所有图片id
        List<Long> pictureIds = pictureList.stream()
                .map(PictureDO::getId)
                .collect(Collectors.toList());
        // 查询当前用户对这些图片的点赞状态和分享状态
        Map<Long, Integer> pictureIdIsLikeMap;
        Map<Long, Integer> pictureIdIsShareMap;
        if (loginUserID != null && !pictureIds.isEmpty()) {
            List<PictureLikeDO> likes = pictureLikeMapper.listByUserAndPictures(loginUserID, pictureIds);
            pictureIdIsLikeMap = likes.stream()
                    .collect(Collectors.toMap(
                            PictureLikeDO::getPictureId,
                            PictureLikeDO::getIsLiked,
                            (existing, replacement) -> existing // 处理重复键
                    ));
            List<PictureShareDO> shares = pictureShareMapper.listByUserAndPictures(loginUserID, pictureIds);
            pictureIdIsShareMap = shares.stream()
                    .collect(Collectors.toMap(
                            PictureShareDO::getPictureId,
                            PictureShareDO::getIsShared,
                            (existing, replacement) -> existing // 处理重复键
                    ));
        } else {
            pictureIdIsLikeMap = new HashMap<>();
            pictureIdIsShareMap = new HashMap<>();
        }

        // 关联查询用户信息
        Set<Long> userIdSet = pictureList.stream().map(PictureDO::getUserId).collect(Collectors.toSet());
        Map<Long, List<UserDO>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(UserDO::getId));
        // 填充用户信息、点赞信息、分享信息
        Long finalLoginUserID = loginUserID;
        PictureRespDTOList.forEach(PictureRespDTO -> {
            // 填充用户信息
            Long userId = PictureRespDTO.getUserId();
            UserDO user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            PictureRespDTO.setUser(userService.getUser(user));
            // 填充点赞信息
            // 填充点赞状态
            if (finalLoginUserID != null) {
                Integer isLike = pictureIdIsLikeMap.get(PictureRespDTO.getId());
                PictureRespDTO.setIsLiked(isLike != null ? isLike : 0);
            } else {
                PictureRespDTO.setIsLiked(0); // 未登录默认false
            }
            // 填充分享信息
            if (finalLoginUserID != null) {
                Integer isShare = pictureIdIsShareMap.get(PictureRespDTO.getId());
                PictureRespDTO.setIsShared(isShare != null ? isShare : 0);
            } else {
                PictureRespDTO.setIsShared(0); // 未登录默认false
            }

        });
        PictureRespDTOPage.setRecords(PictureRespDTOList);
        return PictureRespDTOPage;
    }





    private void validPicture(PictureDO picture) {
        ExceptionTrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        Long id = picture.getId();
        String url = picture.getUrl();
        String introduction = picture.getIntroduction();
        // 修改数据时，id 不能为空，有参数则校验
        ExceptionTrowUtils.throwIf(ObjUtil.isNull(id), ErrorCode.PARAMS_ERROR, "id 不能为空");
        if (StrUtil.isNotBlank(url)) {
            ExceptionTrowUtils.throwIf(url.length() > 1024, ErrorCode.PARAMS_ERROR, "url 过长");
        }
        if (StrUtil.isNotBlank(introduction)) {
            ExceptionTrowUtils.throwIf(introduction.length() > 800, ErrorCode.PARAMS_ERROR, "简介过长");
        }
    }


}




